home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / unzip42.zip / UNZIP.C < prev    next >
C/C++ Source or Header  |  1992-03-19  |  47KB  |  1,195 lines

  1. /*---------------------------------------------------------------------------
  2.  
  3.   unzip.c
  4.  
  5.   UnZip - a zipfile extraction utility.  See below for make instructions, or
  6.   read the comments in Makefile for a more detailed explanation.  To join 
  7.   Info-ZIP, send a message to info-zip-request@cs.ucla.edu.
  8.  
  9.   UnZip 4.x is nearly a complete rewrite of version 3.x, mainly to allow 
  10.   access to zipfiles via the central directory (and hence to the OS bytes, 
  11.   so we can make intelligent decisions about what to do with the extracted 
  12.   files).  Based on unzip.c 3.15+ and zipinfo.c 0.90.  For a complete revi-
  13.   sion history, see UnzpHist.zip at Info-ZIP headquarters (below).  For a 
  14.   (partial) list of the many (near infinite) contributors, see "CONTRIBS" in
  15.   the UnZip source distribution.
  16.  
  17.   ---------------------------------------------------------------------------
  18.  
  19.   To compile (partial instructions):
  20.  
  21.      under Unix (cc):  make <system name>
  22.        (type "make list" for a list of valid names, or read Makefile for 
  23.         details.  "make unzip" works for most systems.  If you have a NEW
  24.         system, not covered by any of the existing targets, send FULL infor-
  25.         mation--hardware, OS, versions, etc.--to zip-bugs@cs.ucla.edu)
  26.  
  27.      under MS-DOS (TurboC):  make -fMAKEFILE.DOS  for command line compiles
  28.        (or use the integrated environment and the included files TCCONFIG.TC
  29.         and UNZIP.PRJ.  Tweak for your environment.)
  30.  
  31.      under MS-DOS (MSC):  make MAKEFILE.DOS
  32.        (or use Makefile if you have MSC 6.0:  "nmake msc_dos")
  33.  
  34.      under OS/2 (MSC):  make MAKEFILE.DOS   (edit appropriately)
  35.        (or use Makefile if you have MSC 6.0:  "nmake msc_os2")
  36.  
  37.      under Atari OS:  needs a little work yet...
  38.  
  39.      under VMS:  DEFINE LNK$LIBRARY SYS$LIBRARY:VAXCRTL.OLB   (see VMSNOTES)
  40.                  CC UNZIP,FILE_IO,MAPNAME,MATCH,...,UNSHRINK
  41.                  LINK UNZIP,FILE_IO,MAPNAME,MATCH,...,UNSHRINK
  42.                  UNZIP :== $DISKNAME:[DIRECTORY]UNZIP.EXE
  43.  
  44.      under Macintosh OS:   Double click on unzip.make.  Press <Command>-M.
  45.  
  46.   ---------------------------------------------------------------------------
  47.  
  48.   Version:  unzip42.{arc | tar.Z | zip | zoo} for Unix, VMS, OS/2, MS-DOS,
  49.               Mac & Amiga.
  50.   Source:  valeria.cs.ucla.edu (131.179.64.36) in /pub
  51.            wuarchive.wustl.edu (128.252.135.4) in /mirrors/misc/unix
  52.            wsmr-simtel20.army.mil (192.88.110.20) in pd1:[misc.unix]
  53.   Copyrights:  see accompanying file "COPYING" in UnZip source distribution.
  54.  
  55.   ---------------------------------------------------------------------------*/
  56.  
  57.  
  58.  
  59.  
  60.  
  61. #include "unzip.h"              /* includes, defines, and macros */
  62.  
  63. /* #define VERSION  "v4.20x BETA of 3-20-92"  internal beta level */
  64. #define VERSION  "v4.2 of 20 March 1992"
  65. #define PAKFIX   /* temporary solution to PAK-created zipfiles */
  66.  
  67.  
  68.  
  69.  
  70.  
  71. /**********************/
  72. /*  Global Variables  */
  73. /**********************/
  74.  
  75. int aflag;            /* -a: do ASCII to EBCDIC translation, or CR-LF  */
  76. /* int bflag; RESERVED for -b: extract as binary */
  77. int cflag;            /* -c: output to stdout */
  78. int fflag;            /* -f: "freshen" (extract only newer files) */
  79. int jflag;            /* -j: junk pathnames */
  80. int overwrite_none;   /* -n: never overwrite files (no prompting) */
  81. int overwrite_all;    /* -o: OK to overwrite files without prompting */
  82. int force_flag;       /* (shares -o for now): force to override errors, etc. */
  83. int quietflg;         /* -q: produce a lot less output */
  84. #ifdef DOS_OS2          /*    to CR or LF conversion of extracted files */
  85.    int sflag;         /* -s: allow spaces (blanks) in filenames */
  86. #endif /* DOS_OS2 */
  87. int tflag;            /* -t: test */
  88. int uflag;            /* -u: "update" (extract only newer & brand-new files) */
  89. static int U_flag;    /* -U: leave filenames in upper or mixed case */
  90. static int vflag;     /* -v: view directory (only used in unzip.c) */
  91. int V_flag;           /* -V: don't strip VMS version numbers */
  92. #ifdef VMS
  93.    int secinf;        /* -X: keep owner/protection */
  94. #endif /* VMS */
  95. int zflag;            /* -z: display only the archive comment */
  96. int process_all_files;
  97.  
  98. longint csize;        /* used by list_files(), ReadByte(): must be signed */
  99. longint ucsize;       /* used by list_files(), unReduce(), unImplode() */
  100.  
  101. char *fnames[2] = {"*", NULL};   /* default filenames vector */
  102. char **fnv = fnames;
  103. char sig[5];
  104. char answerbuf[10];
  105.  
  106. min_info info[DIR_BLKSIZ], *pInfo=info;
  107.  
  108. #ifdef OS2
  109.    int longname;           /* used only in mapname.c and file_io.c */
  110.    char longfilename[FILNAMSIZ];
  111. #endif /* OS2 */
  112.  
  113. #ifdef CRYPT
  114.    char *key = NULL;       /* password with which to decrypt data, or NULL */
  115. #endif /* CRYPT */
  116.  
  117. /*---------------------------------------------------------------------------
  118.     unShrink/unReduce/unImplode working storage:
  119.   ---------------------------------------------------------------------------*/
  120.  
  121. /* prefix_of (for unShrink) is biggest storage area, esp. on Crays...space */
  122. /*  is shared by lit_nodes (unImplode) and followers (unReduce) */
  123.  
  124. short prefix_of[HSIZE + 1];     /* (8193 * sizeof(short)) */
  125. #ifdef MACOS
  126.    byte *suffix_of;
  127.    byte *stack;
  128. #else
  129.    byte suffix_of[HSIZE + 1];   /* also s-f length_nodes (smaller) */
  130.    byte stack[HSIZE + 1];       /* also s-f distance_nodes (smaller) */
  131. #endif
  132.  
  133. ULONG crc32val;
  134.  
  135. ULONG mask_bits[] =
  136. {0x00000000L,
  137.  0x00000001L, 0x00000003L, 0x00000007L, 0x0000000fL,
  138.  0x0000001fL, 0x0000003fL, 0x0000007fL, 0x000000ffL,
  139.  0x000001ffL, 0x000003ffL, 0x000007ffL, 0x00000fffL,
  140.  0x00001fffL, 0x00003fffL, 0x00007fffL, 0x0000ffffL,
  141.  0x0001ffffL, 0x0003ffffL, 0x0007ffffL, 0x000fffffL,
  142.  0x001fffffL, 0x003fffffL, 0x007fffffL, 0x00ffffffL,
  143.  0x01ffffffL, 0x03ffffffL, 0x07ffffffL, 0x0fffffffL,
  144.  0x1fffffffL, 0x3fffffffL, 0x7fffffffL, 0xffffffffL};
  145.  
  146. /*---------------------------------------------------------------------------
  147.     Input file variables:
  148.   ---------------------------------------------------------------------------*/
  149.  
  150. byte *inbuf, *inptr;     /* input buffer (any size is legal) and pointer */
  151. int incnt;
  152.  
  153. ULONG bitbuf;
  154. int bits_left;
  155. boolean zipeof;
  156.  
  157. int zipfd;               /* zipfile file handle */
  158. char zipfn[FILNAMSIZ];
  159.  
  160. char local_hdr_sig[5] = "\120";    /* remaining signature bytes come later   */
  161. char central_hdr_sig[5] = "\120";  /*  (must initialize at runtime so unzip  */
  162. char end_central_sig[5] = "\120";  /*  executable won't look like a zipfile) */
  163.  
  164. cdir_file_hdr crec;      /* used in unzip.c, extract.c, misc.c */
  165. local_file_hdr lrec;     /* used in unzip.c, extract.c */
  166. ecdir_rec ecrec;         /* used in unzip.c, extract.c */
  167. struct stat statbuf;     /* used by main(), mapped_name(), check_for_newer() */
  168.  
  169. longint extra_bytes = 0;        /* used in unzip.c, misc.c */
  170. longint cur_zipfile_bufstart;   /* extract_or_test_files, readbuf, ReadByte */
  171.  
  172. byte *extra_field = NULL;       /* currently used by VMS version only */
  173.  
  174. /*---------------------------------------------------------------------------
  175.     Output stream variables:
  176.   ---------------------------------------------------------------------------*/
  177.  
  178. byte *outbuf;                   /* buffer for rle look-back */
  179. byte *outptr;
  180. byte *outout;                   /* scratch pad for ASCII-native trans */
  181. longint outpos;                 /* absolute position in outfile */
  182. int outcnt;                     /* current position in outbuf */
  183. int outfd;
  184. int disk_full;
  185. char filename[FILNAMSIZ];
  186.  
  187. /*---------------------------------------------------------------------------
  188.     unzip.c static global variables (visible only within this file):
  189.   ---------------------------------------------------------------------------*/
  190.  
  191. static byte *hold;
  192. static char unkn[10];
  193. static longint ziplen;
  194. static UWORD methnum;
  195.  
  196. /*---------------------------------------------------------------------------
  197.     unzip.c repeated error messages (we use all of these at least twice)
  198.   ---------------------------------------------------------------------------*/
  199.  
  200. char *EndSigMsg = "\nwarning:\
  201.   didn't find end-of-central-dir signature at end of central dir.\n";
  202. char *CentSigMsg =
  203.   "error:  expected central file header signature not found (file #%u).\n";
  204. char *SeekMsg =
  205.   "error:  attempt to seek before beginning of zipfile\n%s";
  206.  
  207. #ifdef VMS
  208. char *ReportMsg = "\
  209.   (please check that you have transferred or created the zipfile in the\n\
  210.   appropriate BINARY mode--this includes ftp, Kermit, AND unzip'd zipfiles)\n";
  211. #else /* !VMS */
  212. char *ReportMsg = "\
  213.   (please check that you have transferred or created the zipfile in the\n\
  214.   appropriate BINARY mode and that you have compiled unzip properly)\n";
  215. #endif /* ?VMS */
  216.  
  217.  
  218.  
  219.  
  220. /******************/
  221. /*  Main program  */
  222. /******************/
  223.  
  224. main(argc, argv)        /* return PK-type error code (except under VMS) */
  225. int argc;
  226. char *argv[];
  227. {
  228.     char *s;
  229.     int c, error=FALSE;
  230.  
  231.  
  232. /*---------------------------------------------------------------------------
  233.     Macintosh initialization code.
  234.   ---------------------------------------------------------------------------*/
  235.  
  236. #ifdef MACOS
  237. #ifdef THINK_C
  238.     #include <console.h>
  239.     static char *argstr[30], args[30*64];
  240.  
  241.     Point   p;
  242.     SFTypeList  sfT;
  243.     int a;
  244.     EventRecord theEvent;
  245.     short   eMask;
  246.     SFReply  fileRep;
  247. #endif /* THINK_C */
  248.  
  249.     typedef struct sf_node {        /* node in a true shannon-fano tree */
  250.         UWORD left;                 /* 0 means leaf node */
  251.         UWORD right;                /*   or value if leaf node */
  252.     } sf_node;
  253.  
  254.     extern sf_node *lit_nodes, *length_nodes, *distance_nodes;
  255.  
  256. #ifdef MCH_MACINTOSH
  257.     defSpin(0x20);
  258. #endif
  259.  
  260.     suffix_of = (byte *)calloc(HSIZE+1, sizeof(byte));
  261.     stack = (byte *)calloc(HSIZE+1, sizeof(byte));
  262.     length_nodes = (sf_node *) suffix_of;  /* 2*LENVALS nodes */
  263.     distance_nodes = (sf_node *) stack;    /* 2*DISTVALS nodes */
  264.  
  265. #ifdef THINK_C   
  266.     for (a=0; a<30; a+=1)
  267.         argstr[a] = &args[a*64];
  268. start:
  269.     tflag=vflag=cflag=aflag=jflag=U_flag=quietflg=fflag=uflag=zflag = 0;
  270.     local_hdr_sig[1]=central_hdr_sig[1]=end_central_sig[1]='\0';
  271.  
  272.     argc = ccommand(&argv);
  273.     SetPt(&p, 40,40);
  274.  
  275.     SFGetFile(p, "\pSpecify ZIP file:", 0L, -1, sfT, 0L, &fileRep);
  276.     if (!fileRep.good)
  277.         exit(1);
  278.     macfstest(fileRep.vRefNum);
  279.     SetMacVol(NULL, fileRep.vRefNum);
  280.     for (a=1; a<argc; a+=1)
  281.         if (argv[a][0] == '-')
  282.             BlockMove(argv[a], argstr[a], (strlen(argv[a])>63) ? 64 : strlen(argv[a])+1);
  283.         else
  284.             break;
  285.     PtoCstr((char *)fileRep.fName);
  286.     strcpy(argstr[a], (char *)fileRep.fName);
  287.     for (;a<argc; a+=1)
  288.         BlockMove(argv[a], argstr[a+1], (strlen(argv[a])>63) ? 64 : strlen(argv[a])+1);
  289.     argc+=1;
  290.     argv = argstr;
  291.  
  292.     if (hfsflag == FALSE)   /* can't support directories:  junk pathnames */
  293.         jflag = 1;
  294. #endif /* THINK_C */
  295. #endif /* MACOS */
  296.  
  297. /*---------------------------------------------------------------------------
  298.     Debugging info for checking on structure padding:
  299.   ---------------------------------------------------------------------------*/
  300.  
  301. #ifdef DEBUG_STRUC
  302.     printf("local_file_hdr size: %X\n",
  303.            sizeof(local_file_hdr));
  304.     printf("local_byte_hdr size: %X\n",
  305.            sizeof(local_byte_hdr));
  306.     printf("actual size of local headers: %X\n", LREC_SIZE);
  307.  
  308.     printf("central directory header size: %X\n",
  309.            sizeof(cdir_file_hdr));
  310.     printf("central directory byte header size: %X\n",
  311.            sizeof(cdir_byte_hdr));
  312.     printf("actual size of central dir headers: %X\n", CREC_SIZE);
  313.  
  314.     printf("end central dir record size: %X\n",
  315.            sizeof(ecdir_rec));
  316.     printf("end central dir byte record size: %X\n",
  317.            sizeof(ec_byte_rec));
  318.     printf("actual size of end-central-dir record: %X\n", ECREC_SIZE);
  319. #endif /* DEBUG_STRUC */
  320.  
  321. /*---------------------------------------------------------------------------
  322.     Rip through any command-line options lurking about...
  323.   ---------------------------------------------------------------------------*/
  324.  
  325.     while (--argc > 0 && (*++argv)[0] == '-') {
  326.         s = argv[0] + 1;
  327.         while ((c = *s++) != 0) {    /* "!= 0":  prevent Turbo C warning */
  328.             switch (c) {
  329.             case ('a'):
  330.                 ++aflag;
  331.                 break;
  332. #if 0
  333.             case ('s'):
  334.                 ++sflag;
  335.                 break;
  336. #endif
  337.             case ('c'):
  338.                 ++cflag;
  339. #ifdef NATIVE
  340.                 ++aflag;   /* this is so you can read it on the screen */
  341. #endif
  342.                 break;
  343.             case ('d'):    /* re-create directory structure (now by default) */
  344.                 break;
  345.             case ('e'):    /* just ignore -e, -x options (extract) */
  346.                 break;
  347.             case ('f'):    /* "freshen" (extract only newer files) */
  348.                 ++fflag;
  349.                 ++uflag;
  350.                 break;
  351.             case ('j'):    /* junk pathnames/directory structure */
  352.                 ++jflag;
  353.                 break;
  354.          /* case ('l') is below, after fall-through for 'v' */
  355.             case ('n'):    /* don't overwrite any files */
  356.                 overwrite_none = TRUE;
  357.                 break;
  358.             case ('o'):    /* OK to overwrite files without prompting */
  359.                 overwrite_all = TRUE;
  360.                 force_flag = TRUE;  /* (share -o for now): force to continue */
  361.                 break;
  362.             case ('p'):
  363.                 ++cflag;
  364. #if defined(NATIVE) && !defined(DOS_OS2)
  365.                 ++aflag;
  366. #endif
  367.                 quietflg += 99;
  368.                 break;
  369.             case ('q'):
  370.                 ++quietflg;
  371.                 break;
  372. #ifdef DOS_OS2
  373.             case ('s'):
  374.                 ++sflag;
  375.                 break;
  376. #endif
  377.             case ('t'):
  378.                 ++tflag;
  379.                 break;
  380.             case ('U'):    /* Uppercase flag (i.e., don't convert to lower) */
  381.                 ++U_flag;
  382.                 break;
  383.             case ('u'):    /* "update" (extract only new and newer files) */
  384.                 ++uflag;
  385.                 break;
  386.             case ('V'):    /* Version flag:  retain VMS/DEC-20 file versions */
  387.                 ++V_flag;
  388.                 break;
  389.             case ('v'):
  390.                 ++vflag;
  391.                 /* fall thru */
  392.             case ('l'):
  393.                 ++vflag;
  394.                 break;
  395. #ifdef VMS
  396.             case ('X'):    /* restore owner/protection info (may need privs) */
  397.                 secinf = TRUE;
  398.                 break;
  399. #endif /* VMS */
  400.             case ('x'):    /* extract:  default */
  401.                 break;
  402.             case ('z'):    /* display only the archive comment */
  403.                 ++zflag;
  404.                 break;
  405.             default:
  406.                 error = TRUE;
  407.                 break;
  408.             }
  409.         }
  410.     }
  411.  
  412. /*---------------------------------------------------------------------------
  413.     Make sure we aren't trying to do too many things here.  [This seems like
  414.     kind of a brute-force way to do things; but aside from that, isn't the
  415.     -a option useful when listing the directory (i.e., for reading zipfile
  416.     comments)?  It's a modifier, not an action in and of itself, so perhaps
  417.     it should not be included in the test--certainly, in the case of zipfile
  418.     testing, it can just be ignored.]
  419.   ---------------------------------------------------------------------------*/
  420.  
  421.     if ((aflag && tflag) || (aflag && vflag) || (cflag && tflag) ||
  422.         (cflag && uflag) || (cflag && vflag) || (tflag && uflag) ||
  423.         (tflag && vflag) || (uflag && vflag) || (fflag && overwrite_none)) {
  424.         fprintf(stderr, "error:\
  425.   -at, -av, -ct, -cu, -cv, -fn, -tu, -tv, -uv combinations not allowed\n");
  426.         error = TRUE;
  427.     }
  428.     if (quietflg && zflag)
  429.         quietflg = 0;
  430.     if (overwrite_all && overwrite_none) {
  431.         fprintf(stderr, "caution:  both -n and -o specified; ignoring -o\n");
  432.         overwrite_all = FALSE;
  433.     }
  434.     if ((argc-- == 0) || error)
  435.         RETURN(usage(error));
  436.  
  437. /*---------------------------------------------------------------------------
  438.     Now get the zipfile name from the command line and see if it exists as a
  439.     regular (non-directory) file.  If not, append the ".zip" suffix.  We don't
  440.     immediately check to see if this results in a good name, but we will do so
  441.     later.  In the meantime, see if there are any member filespecs on the com-
  442.     mand line, and if so, set the filename pointer to point at them.
  443.   ---------------------------------------------------------------------------*/
  444.  
  445.     strcpy(zipfn, *argv++);
  446.     if (stat(zipfn, &statbuf) || (statbuf.st_mode & S_IFMT) == S_IFDIR)
  447.         strcat(zipfn, ZSUFX);
  448. #if defined(UNIX) && !defined(VMS)   /* Unix executables have no extension-- */
  449.     else if (statbuf.st_mode & S_IEXEC)  /* might find zip, not zip.zip; etc */
  450.         fprintf(stderr, "\nnote:  file [ %s ] may be an executable\n\n", zipfn);
  451. #endif /* UNIX && !VMS */
  452.  
  453.     if (stat(zipfn, &statbuf)) {/* try again */
  454.         fprintf(stderr, "error:  can't find zipfile [ %s ]\n", zipfn);
  455.         RETURN(9);              /* 9:  file not found */
  456.     } else
  457.         ziplen = statbuf.st_size;
  458.  
  459.     if (argc != 0) {
  460.         fnv = argv;
  461.         process_all_files = FALSE;
  462.     } else
  463.         process_all_files = TRUE;       /* for speed */
  464.  
  465. /*---------------------------------------------------------------------------
  466.     Okey dokey, we have everything we need to get started.  Let's roll.
  467.   ---------------------------------------------------------------------------*/
  468.  
  469.     inbuf = (byte *) malloc(INBUFSIZ + 4);     /* 4 extra for hold[] (below) */
  470.     outbuf = (byte *) malloc(OUTBUFSIZ + 1);   /* 1 extra for string termin. */
  471. #ifndef DOS_OS2
  472.     if (aflag)                  /* if need an ascebc scratch, */
  473.         outout = (byte *) malloc(OUTBUFSIZ);
  474.     else                        /*  allocate it... */
  475. #endif /* !DOS_OS2 */
  476.         outout = outbuf;        /*  else just point to outbuf */
  477.  
  478.     if ((inbuf == NULL) || (outbuf == NULL) || (outout == NULL)) {
  479.         fprintf(stderr, "error:  can't allocate unzip buffers\n");
  480.         RETURN(4);              /* 4-8:  insufficient memory */
  481.     }
  482.     hold = &inbuf[INBUFSIZ];    /* to check for boundary-spanning signatures */
  483.  
  484. #ifdef THINK_C
  485.     if (!process_zipfile())
  486.         goto start;
  487. #else
  488.     RETURN(process_zipfile());  /* keep passing errors back... */
  489. #endif
  490.  
  491. }       /* end main() */
  492.  
  493.  
  494.  
  495.  
  496.  
  497. /**********************/
  498. /*  Function usage()  */
  499. /**********************/
  500.  
  501. int usage(error)   /* return PK-type error code */
  502.     int error;
  503. {
  504. #ifdef NATIVE
  505. #ifdef EBCDIC
  506.     char *astring = "-a  convert ASCII to EBCDIC";
  507. #else /* !EBCDIC */
  508.     char *astring = "-a  convert ASCII to native chars";
  509. #endif /* ?EBCDIC *?
  510. /*  char *astring = "-a  convert ASCII to " NATIVE;  (ANSI C concatenation)  */
  511.     char *loc_str = "";
  512. #else /* !NATIVE */
  513. #ifdef DOS_OS2
  514.     char *astring = "-a  convert text (LF => CR LF)";
  515.     char *loc_str = "-s  allow spaces in filenames";
  516. #else /* !DOS_OS2 */
  517. #ifdef MACOS
  518.     char *astring = "-a  convert text (CR LF => CR)";
  519.     char *loc_str = "";
  520. #else /* !MACOS:  UNIX, VMS */
  521.     char *astring = "-a  convert text (CR LF => LF)";
  522. #ifdef VMS
  523.     char *loc_str = "-X  restore owner/protection info";
  524. #else /* !VMS */
  525.     char *loc_str = "";
  526. #endif /* ?VMS */
  527. #endif /* ?MACOS */
  528. #endif /* ?DOS_OS2 */
  529. #endif /* ?NATIVE */
  530.     FILE *usagefp;
  531.  
  532.  
  533. /*---------------------------------------------------------------------------
  534.     If user requested usage, send it to stdout; else send to stderr.
  535.   ---------------------------------------------------------------------------*/
  536.  
  537.     if (error)
  538.         usagefp = (FILE *) stderr;
  539.     else
  540.         usagefp = (FILE *) stdout;
  541.  
  542.     fprintf(usagefp, "\
  543. UnZip:  Zipfile Extract %s;  (c) 1989 S.H.Smith and others\n\
  544. Versions 3.0 and later by Info-ZIP.  Bug reports ONLY to zip-bugs@cs.ucla.edu\
  545. \n\n", VERSION);
  546.  
  547.     fprintf(usagefp, "\
  548. Usage: unzip [ -options[modifiers] ] file[.zip] [filespec...]\n\
  549.   -x  extract files (default)                -l  list files (short format)\n\
  550.   -c  extract files to stdout/screen (CRT)   -v  list files (verbose format)\n\
  551.   -f  freshen existing files, create none    -p  extract to pipe, no messages\n\
  552.   -u  update files, create if necessary      -t  test archive integrity\n\
  553.                                              -z  display archive comment\n\
  554. modifiers:\n\
  555.   -n  never overwrite existing files         %s\n", loc_str);
  556.     fprintf(usagefp, "\
  557.   -o  overwrite files WITHOUT prompting      %s\n\
  558.   -j  junk paths (don't make directories)    -U  don't make names lowercase\n\
  559.   -q  quiet mode (-qq => quieter)            -V  retain VMS version numbers\
  560. \n\n\
  561. Examples: (See manual for more information)\n\
  562.   unzip data1 Readme   => extracts file Readme from zipfile data1.zip\n\
  563.   unzip -p foo | more  => send contents of foo.zip via pipe into program more\n\
  564.   unzip -fo foo        => quietly replace existing files if archive files newer\
  565. \n", astring);
  566.  
  567. #ifdef VMS
  568.     fprintf(usagefp, "\
  569.   unzip \"-V\" foo \"Bar\" => must quote uppercase options and filenames in VMS\
  570. \n");
  571. #endif
  572.  
  573.     if (error)
  574.         return 10;    /* 10:  bad or illegal parameters specified */
  575.     else
  576.         return 0;     /* just wanted usage screen: no error */
  577.  
  578. }       /* end function usage() */
  579.  
  580.  
  581.  
  582.  
  583.  
  584. /********************************/
  585. /*  Function process_zipfile()  */
  586. /********************************/
  587.  
  588. int process_zipfile()    /* return PK-type error code */
  589. {
  590.     int error=0, error_in_archive;
  591.     longint real_ecrec_offset, expect_ecrec_offset;
  592.  
  593.  
  594. /*---------------------------------------------------------------------------
  595.     Open the zipfile for reading and in BINARY mode to prevent CR/LF trans-
  596.     lation, which would corrupt the bitstreams.
  597.   ---------------------------------------------------------------------------*/
  598.  
  599. #ifdef VMS
  600.     {
  601.         int rtype;
  602.  
  603.         VMSmunch(zipfn, GET_RTYPE, (char *)&rtype);
  604.         if (rtype == FAT$C_VARIABLE) {
  605.             fprintf(stderr,
  606.      "\n     Error:  zipfile is in variable-length record format.  Please\n\
  607.      run \"bilf l %s\" to convert the zipfile to stream-LF\n\
  608.      record format.  (Bilf.exe, bilf.c and make_bilf.com are included\n\
  609.      in the VMS unzip distribution.)\n\n", zipfn);
  610.             return 2;           /* 2:  error in zipfile */
  611.         }
  612.         rtype = FAT$C_STREAMLF; /* Unix I/O loves it */
  613.         VMSmunch(zipfn, CHANGE_RTYPE, (char *)&rtype);
  614.     }
  615. #endif
  616.     if (open_input_file())      /* this should never happen, given the */
  617.         return (9);             /*   stat() test in main(), but... */
  618.  
  619. /*---------------------------------------------------------------------------
  620.     Reconstruct the various PK signature strings; find and process the cen-
  621.     tral directory; list, extract or test member files as instructed; and
  622.     close the zipfile.
  623.   ---------------------------------------------------------------------------*/
  624.  
  625.     strcat(local_hdr_sig, LOCAL_HDR_SIG);
  626.     strcat(central_hdr_sig, CENTRAL_HDR_SIG);
  627.     strcat(end_central_sig, END_CENTRAL_SIG);
  628.  
  629.     if (find_end_central_dir()) /* not found; nothing to do */
  630.         return (2);             /* 2:  error in zipfile */
  631.  
  632.     real_ecrec_offset = cur_zipfile_bufstart+(inptr-inbuf);
  633. #ifdef TEST
  634.     printf("\n  found end-of-central-dir signature at offset %ld (%.8lXh)\n",
  635.       real_ecrec_offset, real_ecrec_offset);
  636.     printf("    from beginning of file; offset %d (%.4Xh) within block\n",
  637.       inptr-inbuf, inptr-inbuf);
  638. #endif
  639.  
  640.     if ((error_in_archive = process_end_central_dir()) > 1)
  641.         return (error_in_archive);
  642.  
  643.     if (zflag)
  644.         return (0);
  645.  
  646. #ifndef PAKFIX
  647.     if (ecrec.number_this_disk == 0) {
  648. #else /* PAKFIX */
  649.     if ((ecrec.number_this_disk == 0)  ||
  650.         (error = ((ecrec.number_this_disk == 1) &&
  651.                   (ecrec.num_disk_with_start_central_dir == 1)) )) {
  652.  
  653.         if (error) {
  654.             fprintf(stderr,
  655.      "\n     Warning:  zipfile claims to be disk 2 of a two-part archive;\n\
  656.      attempting to process anyway.  If no further errors occur, this\n\
  657.      archive was probably created by PAK v2.5 or earlier.  This bug\n\
  658.      was reported to NoGate and should have been fixed by mid-1991.\n\n");
  659.             error_in_archive = 1;  /* 1:  warning */
  660.         }
  661. #endif /* ?PAKFIX */
  662.         expect_ecrec_offset = ecrec.offset_start_central_directory +
  663.                               ecrec.size_central_directory;
  664.         if ((extra_bytes = real_ecrec_offset - expect_ecrec_offset) < 0) {
  665.             fprintf(stderr, "\nerror:  missing %ld bytes in zipfile (\
  666. attempting to process anyway)\n\n", -extra_bytes);
  667.             error_in_archive = 2;       /* 2:  (weak) error in zipfile */
  668.         } else if (extra_bytes > 0) {
  669.             if ((ecrec.offset_start_central_directory == 0) &&
  670.                 (ecrec.size_central_directory != 0))   /* zip 1.5 -go bug */
  671.             {
  672.                 fprintf(stderr, "\nerror:  NULL central directory offset (\
  673. attempting to process anyway)\n\n");
  674.                 ecrec.offset_start_central_directory = extra_bytes;
  675.                 extra_bytes = 0;
  676.                 error_in_archive = 2;   /* 2:  (weak) error in zipfile */
  677.             } else {
  678.                 fprintf(stderr, "\nwarning:  extra %ld bytes at beginning or\
  679.  within zipfile\n          (attempting to process anyway)\n\n", extra_bytes);
  680.                 error_in_archive = 1;   /* 1:  warning error */
  681.             }
  682.         }
  683.         LSEEK( ecrec.offset_start_central_directory )
  684.         if (vflag)
  685.             error = list_files();               /* LIST 'EM */
  686.         else
  687.             error = extract_or_test_files();    /* EXTRACT OR TEST 'EM */
  688.         if (error > error_in_archive)   /* don't overwrite stronger error */
  689.             error_in_archive = error;   /*  with (for example) a warning */
  690.     } else {
  691.         fprintf(stderr, "\nerror:  zipfile is part of multi-disk archive \
  692. (sorry, not supported).\n");
  693.         fprintf(stderr, "Please report to zip-bugs@cs.ucla.edu\n");
  694.         error_in_archive = 11;  /* 11:  no files found */
  695.     }
  696.  
  697.     close(zipfd);
  698. #ifdef VMS
  699.     VMSmunch(zipfn, RESTORE_RTYPE, NULL);
  700. #endif
  701.     return (error_in_archive);
  702.  
  703. }       /* end function process_zipfile() */
  704.  
  705.  
  706.  
  707.  
  708.  
  709. /************************************/
  710. /*  Function find_end_central_dir() */
  711. /************************************/
  712.  
  713. int find_end_central_dir()
  714. /* return 0 if found, 1 otherwise */
  715. {
  716.     int i, numblks;
  717.     longint tail_len;
  718.  
  719.  
  720.  
  721. /*---------------------------------------------------------------------------
  722.     Treat case of short zipfile separately.
  723.   ---------------------------------------------------------------------------*/
  724.  
  725.     if (ziplen <= INBUFSIZ) {
  726.         lseek(zipfd, 0L, SEEK_SET);
  727.         if ((incnt = read(zipfd,(char *)inbuf,(unsigned int)ziplen)) == ziplen)
  728.  
  729.             /* 'P' must be at least 22 bytes from end of zipfile */
  730.             for ( inptr = inbuf+ziplen-22  ;  inptr >= inbuf  ;  --inptr )
  731.                 if ( (ascii_to_native(*inptr) == 'P')  &&
  732.                       !strncmp((char *)inptr, end_central_sig, 4) ) {
  733.                     incnt -= inptr - inbuf;
  734.                     return(0);  /* found it! */
  735.                 }               /* ...otherwise fall through & fail */
  736.  
  737. /*---------------------------------------------------------------------------
  738.     Zipfile is longer than INBUFSIZ:  may need to loop.  Start with short
  739.     block at end of zipfile (if not TOO short).
  740.   ---------------------------------------------------------------------------*/
  741.  
  742.     } else {
  743.         if ((tail_len = ziplen % INBUFSIZ) > ECREC_SIZE) {
  744.             cur_zipfile_bufstart = lseek(zipfd, ziplen-tail_len, SEEK_SET);
  745.             if ((incnt = read(zipfd,(char *)inbuf,(unsigned int)tail_len)) != tail_len)
  746.                 goto fail;      /* shut up, it's expedient. */
  747.  
  748.             /* 'P' must be at least 22 bytes from end of zipfile */
  749.             for ( inptr = inbuf+tail_len-22  ;  inptr >= inbuf  ;  --inptr )
  750.                 if ( (ascii_to_native(*inptr) == 'P')  &&
  751.                       !strncmp((char *)inptr, end_central_sig, 4) ) {
  752.                     incnt -= inptr - inbuf;
  753.                     return(0);  /* found it! */
  754.                 }               /* ...otherwise search next block */
  755.             strncpy((char *)hold, (char *)inbuf, 3);    /* sig may span block
  756.                                                            boundary */
  757.  
  758.         } else {
  759.             cur_zipfile_bufstart = ziplen - tail_len;
  760.         }
  761.  
  762.         /*
  763.          * Loop through blocks of zipfile data, starting at the end and going
  764.          * toward the beginning.  Need only check last 65557 bytes of zipfile:
  765.          * comment may be up to 65535 bytes long, end-of-central-directory rec-
  766.          * ord is 18 bytes (shouldn't hardcode this number, but what the hell:
  767.          * already did so above (22=18+4)), and sig itself is 4 bytes.
  768.          */
  769.  
  770.         /*          ==amt to search==   ==done==   ==rounding==     =blksiz= */
  771.         numblks = ( min(ziplen,65557) - tail_len + (INBUFSIZ-1) ) / INBUFSIZ;
  772.  
  773.         for ( i = 1  ;  i <= numblks  ;  ++i ) {
  774.             cur_zipfile_bufstart -= INBUFSIZ;
  775.             lseek(zipfd, cur_zipfile_bufstart, SEEK_SET);
  776.             if ((incnt = read(zipfd,(char *)inbuf,INBUFSIZ)) != INBUFSIZ)
  777.                 break;          /* fall through and fail */
  778.  
  779.             for ( inptr = inbuf+INBUFSIZ-1  ;  inptr >= inbuf  ;  --inptr )
  780.                 if ( (ascii_to_native(*inptr) == 'P')  &&
  781.                       !strncmp((char *)inptr, end_central_sig, 4) ) {
  782.                     incnt -= inptr - inbuf;
  783.                     return(0);  /* found it! */
  784.                 }
  785.             strncpy((char *)hold, (char *)inbuf, 3);    /* sig may span block
  786.                                                            boundary */
  787.         }
  788.  
  789.     } /* end if (ziplen > INBUFSIZ) */
  790.  
  791. /*---------------------------------------------------------------------------
  792.     Searched through whole region where signature should be without finding
  793.     it.  Print informational message and die a horrible death.
  794.   ---------------------------------------------------------------------------*/
  795.  
  796. fail:
  797.  
  798.     fprintf(stderr, "\nFile:  %s\n\n\
  799.      End-of-central-directory signature not found.  Either this file is not\n\
  800.      a zipfile, or it constitutes one disk of a multi-part archive.  In the\n\
  801.      latter case the central directory and zipfile comment will be found on\n\
  802.      the last disk(s) of this archive.\n", zipfn);
  803.     return(1);
  804.  
  805. }       /* end function find_end_central_dir() */
  806.  
  807.  
  808.  
  809.  
  810.  
  811. /***************************************/
  812. /*  Function process_end_central_dir() */
  813. /***************************************/
  814.  
  815. int process_end_central_dir()    /* return PK-type error code */
  816. {
  817.     ec_byte_rec byterec;
  818.     int error=0;
  819.  
  820.  
  821. /*---------------------------------------------------------------------------
  822.     Read the end-of-central-directory record and do any necessary machine-
  823.     type conversions (byte ordering, structure padding compensation) by
  824.     reading data into character array, then copying to struct.
  825.   ---------------------------------------------------------------------------*/
  826.  
  827.     if (readbuf((char *) byterec, ECREC_SIZE+4) <= 0)
  828.         return (51);
  829.  
  830.     ecrec.number_this_disk =
  831.         makeword(&byterec[NUMBER_THIS_DISK]);
  832.     ecrec.num_disk_with_start_central_dir =
  833.         makeword(&byterec[NUM_DISK_WITH_START_CENTRAL_DIR]);
  834.     ecrec.num_entries_centrl_dir_ths_disk =
  835.         makeword(&byterec[NUM_ENTRIES_CENTRL_DIR_THS_DISK]);
  836.     ecrec.total_entries_central_dir =
  837.         makeword(&byterec[TOTAL_ENTRIES_CENTRAL_DIR]);
  838.     ecrec.size_central_directory =
  839.         makelong(&byterec[SIZE_CENTRAL_DIRECTORY]);
  840.     ecrec.offset_start_central_directory =
  841.         makelong(&byterec[OFFSET_START_CENTRAL_DIRECTORY]);
  842.     ecrec.zipfile_comment_length =
  843.         makeword(&byterec[ZIPFILE_COMMENT_LENGTH]);
  844.  
  845. /*---------------------------------------------------------------------------
  846.     Get the zipfile comment, if any, and print it out.  (Comment may be up
  847.     to 64KB long.  May the fleas of a thousand camels infest the armpits of
  848.     anyone who actually takes advantage of this fact.)  Then position the
  849.     file pointer to the beginning of the central directory and fill buffer.
  850.   ---------------------------------------------------------------------------*/
  851.  
  852.     if (ecrec.zipfile_comment_length && !quietflg) {
  853.         if (!zflag)
  854.           printf("[%s] comment:\n", zipfn);
  855.         if (do_string(ecrec.zipfile_comment_length,DISPLAY)) {
  856.             fprintf(stderr, "\ncaution:  zipfile comment truncated\n");
  857.             error = 1;          /* 1:  warning error */
  858.         }
  859. #if 0
  860.         if (!zflag)
  861.           printf("\n\n");       /* what the heck is this doing here?! */
  862. #endif
  863.     }
  864.  
  865.     return (error);
  866.  
  867. }       /* end function process_end_central_dir() */
  868.  
  869.  
  870.  
  871.  
  872.  
  873. /**************************/
  874. /*  Function list_files() */
  875. /**************************/
  876.  
  877. int list_files()    /* return PK-type error code */
  878. {
  879.     char **fnamev;
  880.     int do_this_file=FALSE, ratio, error, error_in_archive=0;
  881.     int which_hdr=(vflag>1);
  882.     UWORD j, yr, mo, dy, hh, mm, members=0;
  883.     ULONG tot_csize=0L, tot_ucsize=0L;
  884.     min_info info;
  885.     static char *method[NUM_METHODS+1] =
  886.         {"Stored", "Shrunk", "Reduce1", "Reduce2", "Reduce3", "Reduce4",
  887.          "Implode", "Token", "Deflate", unkn};
  888.     static char *Headers[][2] = {
  889.         {" Length    Date    Time    Name",
  890.          " ------    ----    ----    ----"},
  891.         {" Length  Method   Size  Ratio   Date    Time   CRC-32     Name",
  892.          " ------  ------   ----  -----   ----    ----   ------     ----"}
  893.     };
  894.  
  895.  
  896.  
  897. /*---------------------------------------------------------------------------
  898.     Unlike extract_or_test_files(), this routine confines itself to the cen-
  899.     tral directory.  Thus its structure is somewhat simpler, since we can do
  900.     just a single loop through the entire directory, listing files as we go.
  901.  
  902.     So to start off, print the heading line and then begin main loop through
  903.     the central directory.  The results will look vaguely like the following:
  904.  
  905.   Length  Method   Size  Ratio   Date    Time   CRC-32     Name ("^" ==> case
  906.   ------  ------   ----  -----   ----    ----   ------     ----   conversion)
  907.    44004  Implode  13041  71%  11-02-89  19:34  8b4207f7   Makefile.UNIX
  908.     3438  Shrunk    2209  36%  09-15-90  14:07  a2394fd8  ^dos-file.ext
  909.   ---------------------------------------------------------------------------*/
  910.  
  911.     pInfo = &info;
  912.  
  913.     if (quietflg < 2)
  914.         if (U_flag)
  915.             printf("%s\n%s\n", Headers[which_hdr][0], Headers[which_hdr][1]);
  916.         else
  917.             printf("%s (\"^\" ==> case\n%s   conversion)\n", 
  918.               Headers[which_hdr][0], Headers[which_hdr][1]);
  919.  
  920.     for (j = 0; j < ecrec.total_entries_central_dir; ++j) {
  921.  
  922.         if (readbuf(sig, 4) <= 0)
  923.             return (51);        /* 51:  unexpected EOF */
  924.         if (strncmp(sig, central_hdr_sig, 4)) {  /* just to make sure */
  925.             fprintf(stderr, CentSigMsg, j);  /* sig not found */
  926.             fprintf(stderr, ReportMsg);   /* check binary transfers */
  927.             return (3);         /* 3:  error in zipfile */
  928.         }
  929.         if ((error = process_cdir_file_hdr()) != 0)  /* (sets pInfo->lcflag) */
  930.             return (error);     /* only 51 (EOF) defined */
  931.  
  932.         /*
  933.          * We could DISPLAY the filename instead of storing (and possibly trun-
  934.          * cating, in the case of a very long name) and printing it, but that
  935.          * has the disadvantage of not allowing case conversion--and it's nice
  936.          * to be able to see in the listing precisely how you have to type each
  937.          * filename in order for unzip to consider it a match.  Speaking of
  938.          * which, if member names were specified on the command line, check in
  939.          * with match() to see if the current file is one of them, and make a
  940.          * note of it if it is.
  941.          */
  942.  
  943.         if ((error = do_string(crec.filename_length, FILENAME)) != 0) {
  944.             error_in_archive = error;  /*             ^--(uses pInfo->lcflag) */
  945.             if (error > 1)      /* fatal:  can't continue */
  946.                 return (error);
  947.         }
  948.         if ((error = do_string(crec.extra_field_length, EXTRA_FIELD)) != 0) {
  949.             error_in_archive = error;  
  950.             if (error > 1)      /* fatal:  can't continue */
  951.                 return (error);
  952.         }
  953.         if (!process_all_files) {   /* check if specified on command line */
  954.             do_this_file = FALSE;
  955.             fnamev = fnv;       /* don't destroy permanent filename ptr */
  956.             for (--fnamev; *++fnamev;)
  957.                 if (match(filename, *fnamev)) {
  958.                     do_this_file = TRUE;
  959.                     break;      /* found match, so stop looping */
  960.                 }
  961.         }
  962.         /*
  963.          * If current file was specified on command line, or if no names were
  964.          * specified, do the listing for this file.  Otherwise, get rid of the
  965.          * file comment and go back for the next file.
  966.          */
  967.  
  968.         if (process_all_files || do_this_file) {
  969.  
  970.             yr = (((crec.last_mod_file_date >> 9) & 0x7f) + 80) % (unsigned)100;
  971.             mo = (crec.last_mod_file_date >> 5) & 0x0f;
  972.             dy = crec.last_mod_file_date & 0x1f;
  973.  
  974.             /* twist date so it displays according to national convention */
  975.             switch (dateformat()) {
  976.                 case DF_YMD:
  977.                     hh = mo; mo = yr; yr = dy; dy = hh; break;
  978.                 case DF_DMY:
  979.                     hh = mo; mo = dy; dy = hh;
  980.             }
  981.             hh = (crec.last_mod_file_time >> 11) & 0x1f;
  982.             mm = (crec.last_mod_file_time >> 5) & 0x3f;
  983.  
  984.             csize = (longint) crec.compressed_size;
  985.             ucsize = (longint) crec.uncompressed_size;
  986.             if (crec.general_purpose_bit_flag & 1)
  987.                 csize -= 12;    /* if encrypted, don't count encrypt hdr */
  988.  
  989.             ratio = (ucsize == 0) ? 0 :   /* .zip can have 0-length members */
  990.                 ((ucsize > 2000000) ?     /* risk signed overflow if mult. */
  991.                 (int) ((ucsize-csize) / (ucsize/1000L)) + 5 :   /* big */
  992.                 (int) ((1000L*(ucsize-csize)) / ucsize) + 5);   /* small */
  993.  
  994.             switch (which_hdr) {
  995.                 case 0:   /* short form */
  996.                     printf("%7ld  %02u-%02u-%02u  %02u:%02u  %c%s\n",
  997.                       ucsize, mo, dy, yr, hh, mm, (pInfo->lcflag?'^':' '),
  998.                       filename);
  999.                     break;
  1000.                 case 1:   /* verbose */
  1001.                     printf(
  1002.               "%7ld  %-7s%7ld %3d%%  %02u-%02u-%02u  %02u:%02u  %08lx  %c%s\n",
  1003.                       ucsize, method[methnum], csize, ratio/10, mo, dy, yr,
  1004.                       hh, mm, crec.crc32, (pInfo->lcflag?'^':' '), filename);
  1005.             }
  1006.  
  1007.             error = do_string(crec.file_comment_length, (QCOND2? DISPLAY:SKIP));
  1008.             if (error) {
  1009.                 error_in_archive = error;  /* might be just warning */
  1010.                 if (error > 1)  /* fatal */
  1011.                     return (error);
  1012.             }
  1013.             tot_ucsize += (ULONG) ucsize;
  1014.             tot_csize += (ULONG) csize;
  1015.             ++members;
  1016.  
  1017.         } else {        /* not listing this file */
  1018.             SKIP_(crec.file_comment_length)
  1019.         }
  1020.     }                   /* end for-loop (j: files in central directory) */
  1021.  
  1022. /*---------------------------------------------------------------------------
  1023.     Print footer line and totals (compressed size, uncompressed size, number
  1024.     of members in zipfile).
  1025.   ---------------------------------------------------------------------------*/
  1026.  
  1027.     ratio = (tot_ucsize == 0) ? 
  1028.         0 : ((tot_ucsize > 4000000) ?    /* risk unsigned overflow if mult. */
  1029.         (int) ((tot_ucsize - tot_csize) / (tot_ucsize/1000L)) + 5 :
  1030.         (int) ((tot_ucsize - tot_csize) * 1000L / tot_ucsize) + 5);
  1031.  
  1032.     if (quietflg < 2) {
  1033.         switch (which_hdr) {
  1034.         case 0:         /* short */
  1035.             printf("%s\n%7lu                    %-7u\n",
  1036.                    " ------                    -------",
  1037.                    tot_ucsize, members);
  1038.             break;
  1039.         case 1:         /* verbose */
  1040.             printf(
  1041.               "%s\n%7lu         %7lu %3d%%                              %-7u\n",
  1042.               " ------          ------  ---                              -------",
  1043.               tot_ucsize, tot_csize, ratio / 10, members);
  1044.         }
  1045.     }
  1046. /*---------------------------------------------------------------------------
  1047.     Double check that we're back at the end-of-central-directory record.
  1048.   ---------------------------------------------------------------------------*/
  1049.  
  1050.     readbuf(sig, 4);
  1051.     if (strncmp(sig, end_central_sig, 4)) {     /* just to make sure again */
  1052.         fprintf(stderr, EndSigMsg);  /* didn't find end-of-central-dir sig */
  1053. /*      fprintf(stderr, ReportMsg);   */
  1054.         error_in_archive = 1;        /* 1:  warning error */
  1055.     }
  1056.     return (error_in_archive);
  1057.  
  1058. }       /* end function list_files() */
  1059.  
  1060.  
  1061.  
  1062.  
  1063.  
  1064. /**************************************/
  1065. /*  Function process_cdir_file_hdr()  */
  1066. /**************************************/
  1067.  
  1068. int process_cdir_file_hdr()    /* return PK-type error code */
  1069. {
  1070.     cdir_byte_hdr byterec;
  1071.  
  1072.  
  1073. /*---------------------------------------------------------------------------
  1074.     Read the next central directory entry and do any necessary machine-type
  1075.     conversions (byte ordering, structure padding compensation--do so by
  1076.     copying the data from the array into which it was read (byterec) to the
  1077.     usable struct (crec)).
  1078.   ---------------------------------------------------------------------------*/
  1079.  
  1080.     if (readbuf((char *) byterec, CREC_SIZE) <= 0)
  1081.         return (51);            /* 51:  unexpected EOF */
  1082.  
  1083.     crec.version_made_by[0] = byterec[C_VERSION_MADE_BY_0];
  1084.     crec.version_made_by[1] = byterec[C_VERSION_MADE_BY_1];
  1085.     crec.version_needed_to_extract[0] = byterec[C_VERSION_NEEDED_TO_EXTRACT_0];
  1086.     crec.version_needed_to_extract[1] = byterec[C_VERSION_NEEDED_TO_EXTRACT_1];
  1087.  
  1088.     crec.general_purpose_bit_flag =
  1089.         makeword(&byterec[C_GENERAL_PURPOSE_BIT_FLAG]);
  1090.     crec.compression_method =
  1091.         makeword(&byterec[C_COMPRESSION_METHOD]);
  1092.     crec.last_mod_file_time =
  1093.         makeword(&byterec[C_LAST_MOD_FILE_TIME]);
  1094.     crec.last_mod_file_date =
  1095.         makeword(&byterec[C_LAST_MOD_FILE_DATE]);
  1096.     crec.crc32 =
  1097.         makelong(&byterec[C_CRC32]);
  1098.     crec.compressed_size =
  1099.         makelong(&byterec[C_COMPRESSED_SIZE]);
  1100.     crec.uncompressed_size =
  1101.         makelong(&byterec[C_UNCOMPRESSED_SIZE]);
  1102.     crec.filename_length =
  1103.         makeword(&byterec[C_FILENAME_LENGTH]);
  1104.     crec.extra_field_length =
  1105.         makeword(&byterec[C_EXTRA_FIELD_LENGTH]);
  1106.     crec.file_comment_length =
  1107.         makeword(&byterec[C_FILE_COMMENT_LENGTH]);
  1108.     crec.disk_number_start =
  1109.         makeword(&byterec[C_DISK_NUMBER_START]);
  1110.     crec.internal_file_attributes =
  1111.         makeword(&byterec[C_INTERNAL_FILE_ATTRIBUTES]);
  1112.     crec.external_file_attributes =
  1113.         makelong(&byterec[C_EXTERNAL_FILE_ATTRIBUTES]);  /* LONG, not word! */
  1114.     crec.relative_offset_local_header =
  1115.         makelong(&byterec[C_RELATIVE_OFFSET_LOCAL_HEADER]);
  1116.  
  1117.     pInfo->hostnum = min(crec.version_made_by[1], NUM_HOSTS);
  1118. /*  extnum = min( crec.version_needed_to_extract[1], NUM_HOSTS ); */
  1119.     methnum = min(crec.compression_method, NUM_METHODS);
  1120.     if (methnum == NUM_METHODS)
  1121.         sprintf(unkn, "Unk:%03d", crec.compression_method);
  1122.  
  1123. /*---------------------------------------------------------------------------
  1124.     Set flag for lowercase conversion of filename, depending on which OS the
  1125.     file is coming from.  This section could be ifdef'd if some people have
  1126.     come to love DOS uppercase filenames under Unix...but really, guys, get
  1127.     a life. :)  NOTE THAT ALL SYSTEM NAMES NOW HAVE TRAILING UNDERSCORES!!!
  1128.     This is to prevent interference with compiler command-line defines such
  1129.     as -DUNIX, for example, which are then used in "#ifdef UNIX" constructs.
  1130.   ---------------------------------------------------------------------------*/
  1131.  
  1132.     pInfo->lcflag = 0;
  1133.     if (!U_flag)   /* as long as user hasn't specified case-preservation */
  1134.         switch (pInfo->hostnum) {
  1135.             case DOS_OS2_FAT_:
  1136.             case VMS_:
  1137.             case VM_CMS_:           /* all caps? */
  1138.             case CPM_:              /* like DOS, right? */
  1139.         /*  case ATARI_:            ? */
  1140.         /*  case Z_SYSTEM_:         ? */
  1141.         /*  case TOPS20_:           (if we had such a thing...) */
  1142.                 pInfo->lcflag = 1;  /* convert filename to lowercase */
  1143.                 break;
  1144.  
  1145.             default:                /* AMIGA_, UNIX_, (ATARI_), OS2_HPFS_, */
  1146.                 break;              /*   MAC_, (Z_SYSTEM_):  no conversion */
  1147.         }
  1148.  
  1149.     return 0;
  1150.  
  1151. }       /* end function process_cdir_file_hdr() */
  1152.  
  1153.  
  1154.  
  1155.  
  1156.  
  1157. /***************************************/
  1158. /*  Function process_local_file_hdr()  */
  1159. /***************************************/
  1160.  
  1161. int process_local_file_hdr()    /* return PK-type error code */
  1162. {
  1163.     local_byte_hdr byterec;
  1164.  
  1165.  
  1166. /*---------------------------------------------------------------------------
  1167.     Read the next local file header and do any necessary machine-type con-
  1168.     versions (byte ordering, structure padding compensation--do so by copy-
  1169.     ing the data from the array into which it was read (byterec) to the
  1170.     usable struct (lrec)).
  1171.   ---------------------------------------------------------------------------*/
  1172.  
  1173.     if (readbuf((char *) byterec, LREC_SIZE) <= 0)
  1174.         return (51);            /* 51:  unexpected EOF */
  1175.  
  1176.     lrec.version_needed_to_extract[0] = byterec[L_VERSION_NEEDED_TO_EXTRACT_0];
  1177.     lrec.version_needed_to_extract[1] = byterec[L_VERSION_NEEDED_TO_EXTRACT_1];
  1178.  
  1179.     lrec.general_purpose_bit_flag = makeword(&byterec[L_GENERAL_PURPOSE_BIT_FLAG]);
  1180.     lrec.compression_method = makeword(&byterec[L_COMPRESSION_METHOD]);
  1181.     lrec.last_mod_file_time = makeword(&byterec[L_LAST_MOD_FILE_TIME]);
  1182.     lrec.last_mod_file_date = makeword(&byterec[L_LAST_MOD_FILE_DATE]);
  1183.     lrec.crc32 = makelong(&byterec[L_CRC32]);
  1184.     lrec.compressed_size = makelong(&byterec[L_COMPRESSED_SIZE]);
  1185.     lrec.uncompressed_size = makelong(&byterec[L_UNCOMPRESSED_SIZE]);
  1186.     lrec.filename_length = makeword(&byterec[L_FILENAME_LENGTH]);
  1187.     lrec.extra_field_length = makeword(&byterec[L_EXTRA_FIELD_LENGTH]);
  1188.  
  1189.     csize = (longint) lrec.compressed_size;
  1190.     ucsize = (longint) lrec.uncompressed_size;
  1191.  
  1192.     return (0);                 /* 0:  no error */
  1193.  
  1194. }       /* end function process_local_file_hdr() */
  1195.